package com.lft.sparsearray;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 稀疏数组工具包
 * toSparseArray(): 将二维数组转换为稀疏数组
 * toArray(): 将稀疏数组转换为二维数组
 * sparseArrayToIo(): 将稀疏数组存入到磁盘(文件)
 * sparseArrayFromIo()：从磁盘(文件)中读取稀疏数组
 */
public class SparseArrays {
	
	/**
	 * 将一个二维数组转换为稀疏数组
	 * @param arrays 二维数组
	 * @return 稀疏数组
	 */
	public static Object[][] toSparseArray(Object[][] arrays) {
		if (arrays == null) {
			throw new RuntimeException("传入的二维数组不能为空");
		}
		
		// 	稀疏数组结构解析
		//	行	列	值
		// 	11	11	2		第一行，存的是二维数组的行数，列数，有效数据个数
		// 	1	2	1		第二行开始，存储的是二维数组的行、列、具体值。
		// 	2	3	2
		
		// 1. 获取二维数组中的有效数据个数
		int sum = 0;
		for (Object[] array : arrays) {
			for (Object i : array) {
				if (i != null && !i.equals(0)) {
					sum++;
				}
			}
		}
		
		// 2. 创建稀疏数组
		Object[][] sparseArray = new Object[sum + 1][3];
		
		// 3. 获取二维数组的行数
		int row = arrays.length;
		
		// 4. 获取二维数组的列数
		int col = arrays[0].length;
		
		// 5. 给稀疏数组的第一行赋值
		sparseArray[0][0] = row;
		sparseArray[0][1] = col;
		sparseArray[0][2] = sum;
		
		// 6. 遍历二维数组。记录有效数据的行列及值。
		// 记录第几个有效数据
		int count = 0;
		// 遍历二维数组，将有效数据赋值到稀疏数组中。
		for (int i = 0; i < arrays.length; i++) {
			for (int j = 0; j < arrays[i].length; j++) {
				if (arrays[i][j] != null && !arrays[i][j].equals(0)) {
					count++;
					sparseArray[count][0] = i;
					sparseArray[count][1] = j;
					sparseArray[count][2] = arrays[i][j];
				}
			}
		}
		
		// 7. 返回稀疏数组
		return sparseArray;
	}
	
	/**
	 * 将一个稀疏数组还原为二维数组
	 * @param sparseArray 稀疏数组
	 * @return 二维数组
	 */
	public static Object[][] toArray(Object[][] sparseArray) {
		if (sparseArray == null) {
			throw new RuntimeException("传入的稀疏数组不能为空");
		}
		
		// 1. 先读取稀疏数组的第一行，根据第一行的数据，创建原始的二维数组。
		// 得到多少行
		int row = Integer.parseInt(sparseArray[0][0].toString());
		// 得到多少列
		int col = Integer.parseInt(sparseArray[0][1].toString());
		// 得到多少非0值
		int sumRow = Integer.parseInt(sparseArray[0][2].toString());
		// 创建新二维数组
		Object[][] array = new Object[row][col];
		
		// 2. 再读取稀疏数组后几行的数据，并赋给原始的二维数组。
		// 从稀疏数组的第二行开始取值，并赋给新的二维数组
		for (int i = 1; i <= sumRow; i++) {
			int row1 = Integer.parseInt(sparseArray[i][0].toString());
			int col1 = Integer.parseInt(sparseArray[i][1].toString());
			array[row1][col1] = sparseArray[i][2];
		}
		
		// 3. 返回二维数组
		return array;
	}
	
	/**
	 * 将稀疏数组存入到磁盘(文件)中
	 * @param sparseArray 稀疏数组
	 * @param address
	 */
	public static void sparseArrayToIO(Object[][] sparseArray, String address) {
		if (sparseArray == null || address == null || address.length() == 0) {
			throw new RuntimeException("传入的参数有误");
		}
		File file = new File(address);
		if (!file.exists()) {
			try {
				boolean newFile = file.createNewFile();
				System.out.println(newFile ? "文件创建成功" : "文件创建失败");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(file);
			for (Object[] ints : sparseArray) {
				for (Object anInt : ints) {
					fileWriter.write(anInt + "\t");
				}
				fileWriter.write("\r\n");
			}
			fileWriter.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fileWriter != null) {
				try {
					fileWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("~~存入磁盘成功~~");
	}
	
	/**
	 * 在磁盘(文件)中读取出稀疏数组
	 * @param fileAddress
	 * @return
	 */
	public static Object[][] sparseArrayFromIo(String fileAddress) {
		if (fileAddress == null || fileAddress.length() == 0) {
			throw new RuntimeException("传入的参数有误");
		}
		// 获取稀疏数组的行数
		BufferedReader in = null;
		// 行数
		int row = 0;
		try {
			in = new BufferedReader(new FileReader(fileAddress));
			
			// 循环读取文件中的每一行。
			while (in.readLine() != null) {
				row++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		// 获取有效值的个数。
		int sum = row - 1;
		
		// 创建稀疏数组
		Object[][] sparseArray = new Object[sum + 1][3];
		
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(fileAddress));
			// 一行数据
			String line;
			int count = 0;
			// 循环读取文件中的每一行。
			while ((line = br.readLine()) != null) {
				// System.out.println(line);
				// 行中有内容时。根据\t拆分字符串。存入到数组中。
				String[] temp = line.split("\t");
				// for (String s : temp) {
				// 	System.out.println(s);
				// }
				// 遍历数组 将每个值存入到稀疏数组中。
				for (int i = 0; i < temp.length; i++) {
					sparseArray[count][i] = temp[i];
				}
				count++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("~~从磁盘中读取成功~~");
		return sparseArray;
	}
}
